package models

import (
	"strings"
	"io/ioutil"
	"os"
	"path/filepath"
//	"encoding/json"
	"log"
	"hash/fnv"
	"bytes"
	"encoding/binary"
)

const (
	ROUTINES = 4
)

var (
	RootPath, ThumbPath, PreviewPath string
	Dirs map[string]*Imgdir
)

func ScanRoot(root string) (map[string]*Imgdir, error) {

	RootPath = root
	ThumbPath = root + THUMB_DIR
	PreviewPath = root + PREVIEW_DIR
	
	dirs, err := GetAllDirs(root)
	if err != nil || len(dirs) <= 0 {
		log.Println("GetAllDirs err:",err)
		return nil, err
	}

	routines := ROUTINES
	if routines > len(dirs) {
		routines = len(dirs)
	}
	var imgchan = make(chan []Imgdir, routines)
	for i := 0; i < ROUTINES; i++ {
		start := len(dirs) / ROUTINES * i
		end := len(dirs) / ROUTINES + start
		if i + 1 >= ROUTINES {
			end = len(dirs)
		}
		log.Println("start, end : ", start, end)
		
		go func(godirs []string) {

			tmp, err := ScanAllDirs(godirs)
			if err != nil || len(tmp) <= 0 {
				log.Println("goroutines scanalldirs err:",err)
			}

			err = ResizeFill(root, tmp)
			if err != nil {
				log.Println("ScanRoot ResizeFill: ", err)
			}
			
			imgchan <- tmp
		}(dirs[start:end])
	}

	imgdirs := make(map[string]*Imgdir)
	cnt := 0
	for i := 0; i < ROUTINES; i++ {
		var dirslice []Imgdir
		dirslice = <-imgchan

		for _, dir := range dirslice {
			cpdir := dir
			imgdirs[dir.Path] = &cpdir
			log.Println("--- dir path: ", dir.Path)
		}
		cnt += len(dirslice)
	}

	Dirs = imgdirs
	return Dirs, err
}

// 查找root目录下所有的文件夹，子文件夹同级存放
func GetAllDirs(root string) ([]string, error) {

	dirs := make([]string, 0, 10)

	err := filepath.Walk(root,
		func (p string, info os.FileInfo, stats error) error {
			if stats != nil {
				return stats
			}
			if info.IsDir() && !strings.Contains(p, PPROOT) {
				log.Println("getalldirs:", p)
				dirs = append(dirs, p + SPT)
			}
			return nil
		})
	return dirs, err
}

func ScanImgs(dir string) ([]*Imgobj, error) {
	imgs := make([]*Imgobj, 0, 10)
	
	tmp, err := ioutil.ReadDir(dir)
	if err != nil {
		log.Println("ScanImgs", dir, err)
		return nil, err
	}

	for _, file := range tmp {
		log.Println(file.Name())
		if IsImgFile(file.Name()) {
			imgtmp := &Imgobj{Name:file.Name(), Size:file.Size(), Time:file.ModTime()}
			imgs = append(imgs, imgtmp)
		}
	}
	
	return imgs, nil
}

func IsImgFile(path string) bool {
	//log.Println("isimgfile", filepath.Ext(path))
	ext := strings.ToLower(filepath.Ext(path))
	if ext == ".jpg" {
		return true
	}
	return false
}

// 对所有文件夹进行扫描, 返回 imgdir 数组
func ScanAllDirs(dirs []string) ([]Imgdir, error) {
	folders := make([]Imgdir, 0, len(dirs))

	for _, dir := range dirs {
		imgs, err := ScanImgs(dir)
		if len(imgs) <= 0 && err != nil {
			continue
		}
		imgdir := Imgdir{Path:dir, Cnt:len(imgs), Imgs:imgs}
		imgdir.Hash = CalcDirHash(&imgdir)
		folders = append(folders, imgdir)
	}

	return folders, nil
}

func CalcDirHash(dir *Imgdir) (uint64) {
	if dir == nil {
		return 0
	}
	
	h := fnv.New64()
	h.Write([]byte(dir.Path))

	buf := new(bytes.Buffer)
	binary.Write(buf, binary.LittleEndian, dir.Cnt)
	h.Write(buf.Bytes())
	for _, img := range dir.Imgs {
		h.Write([]byte(img.Name))

		buf := new(bytes.Buffer)
		binary.Write(buf, binary.LittleEndian, img.Time)
		h.Write(buf.Bytes())

		buf = new(bytes.Buffer)
		binary.Write(buf, binary.LittleEndian, dir.Cnt)
		h.Write(buf.Bytes())
	}

	return h.Sum64()
}

func SyncImgdir(newdir, basedir *Imgdir) *Imgdir {

	return nil
}

func TrimRootPath(path string) string {
	return string(path[len(RootPath):])
}

// dbg
func PrintDirs(obj map[string]*Imgdir) {
	// tmp, err := json.Marshal(obj)
	// if err != nil {
	// 	return
	// }
	// println(string(tmp))
	
	for _, dir := range obj {
		println(dir.Path)
		for _, img := range dir.Imgs {
			println(img.Name)
		}
	}
}


















